/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package skyproc;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
import java.util.zip.DataFormatException;
import lev.LExporter;
import lev.LFlags;
import lev.LStream;
import skyproc.exceptions.BadParameter;
import skyproc.exceptions.BadRecord;

/**
 * Race Records
 *
 * @author Justin Swanson
 */
public class RACE extends MajorRecordDescription {

    private static final Type[] type = {Type.RACE};
    SubList<SubForm> spells = new SubList<>(Type.SPCT, 4, new SubForm(Type.SPLO));
    SubForm WNAM = new SubForm(Type.WNAM);
    /**
     *
     */
    public BodyTemplate bodyTemplate = new BodyTemplate();
    /**
     *
     */
    public KeywordSet keywords = new KeywordSet();
    DATA DATA = new DATA();
    SubMarkerSet<MFNAMdata> MFNAM = new SubMarkerSet<>(new MFNAMdata(), Type.MNAM, Type.FNAM);
    SubList<SubString> MTNMs = new SubList<>(new SubString(Type.MTNM, false));
    SubFormArray VTCK = new SubFormArray(Type.VTCK, 2);
    SubFormArray DNAM = new SubFormArray(Type.DNAM, 2);
    SubFormArray HCLF = new SubFormArray(Type.HCLF, 2);
    SubData TINL = new SubData(Type.TINL);
    SubData PNAM = new SubData(Type.PNAM);
    SubData UNAM = new SubData(Type.UNAM);
    SubForm ATKR = new SubForm(Type.ATKR);
    SubList<ATKDpackage> ATKDs = new SubList<>(new ATKDpackage());
    SubData NAM1 = new SubData(Type.NAM1);
    SubMarkerSet<EGTmodel> EGTrecords = new SubMarkerSet(new EGTmodel(), Type.MNAM, Type.FNAM);
    SubForm GNAM = new SubForm(Type.GNAM);
    SubData NAM3 = new SubData(Type.NAM3);
    SubMarkerSet<HKXmodel> HKXrecords = new SubMarkerSet(new HKXmodel(), Type.MNAM, Type.FNAM);
    SubForm NAM4 = new SubForm(Type.NAM4);
    SubForm NAM5 = new SubForm(Type.NAM5);
    SubForm NAM7 = new SubForm(Type.NAM7);
    SubForm ONAM = new SubForm(Type.ONAM);
    SubForm LNAM = new SubForm(Type.LNAM);
    SubList<SubString> NAMEs = new SubList<>(new SubString(Type.NAME, true));
    SubList<MTYPpackage> MTYPs = new SubList<>(new MTYPpackage());
    SubData VNAM = new SubData(Type.VNAM);
    SubList<SubForm> QNAM = new SubList<>(new SubForm(Type.QNAM));
    SubForm UNES = new SubForm(Type.UNES);
    SubList<SubString> PHTN = new SubList<>(new SubString(Type.PHTN, true));
    SubList<SubData> PHWT = new SubList<>(new SubData(Type.PHWT));
    SubList<HeadData> headData = new SubList<>(new HeadData());
    SubForm NAM8 = new SubForm(Type.NAM8);
    SubForm RNAM = new SubForm(Type.RNAM);
    SubForm WKMV = new SubForm(Type.WKMV);
    SubForm RNMV = new SubForm(Type.RNMV);
    SubForm SWMV = new SubForm(Type.SWMV);
    SubForm FLMV = new SubForm(Type.FLMV);
    SubForm SNMV = new SubForm(Type.SNMV);

    /**
     *
     */
    RACE() {
	super();

	subRecords.add(spells);
	subRecords.add(WNAM);
	subRecords.add(bodyTemplate);
	subRecords.add(keywords);
	subRecords.add(DATA);
	MFNAM.forceMarkers = true;
	subRecords.add(MFNAM);
	MTNMs.allowDups = false;
	subRecords.add(MTNMs);
	subRecords.add(VTCK);
	subRecords.add(DNAM);
	subRecords.add(HCLF);
	subRecords.add(TINL);
	subRecords.add(PNAM);
	subRecords.add(UNAM);
	subRecords.add(ATKR);
	subRecords.add(ATKDs);
	NAM1.forceExport(true);
	subRecords.add(NAM1);
	EGTrecords.forceMarkers = true;
	subRecords.add(EGTrecords);
	subRecords.add(GNAM);
	NAM3.forceExport(true);
	subRecords.add(NAM3);
	HKXrecords.forceMarkers = true;
	subRecords.add(HKXrecords);
	subRecords.add(NAM4);
	subRecords.add(NAM5);
	subRecords.add(NAM7);
	subRecords.add(ONAM);
	subRecords.add(LNAM);
	subRecords.add(NAMEs);
	subRecords.add(MTYPs);
	subRecords.add(VNAM);
	subRecords.add(QNAM);
	subRecords.add(UNES);
	subRecords.add(PHTN);
	subRecords.add(PHWT);
	subRecords.add(headData);
	subRecords.add(NAM8);
	subRecords.add(RNAM);
	subRecords.add(WKMV);
	subRecords.add(RNMV);
	subRecords.add(SWMV);
	subRecords.add(FLMV);
	subRecords.add(SNMV);
    }

    @Override
    Type[] getTypes() {
	return type;
    }

    @Override
    Record getNew() {
	return new RACE();
    }

    @Override
    void importSubRecords(LStream in) throws BadRecord, DataFormatException, BadParameter, IOException {
	Type nextType;
	while (!in.isDone()) {
	    nextType = getNextType(in);
	    if (nextType == Type.NAM1) {
		subRecords.importSubRecord(in); // import NAM1
		for (int i = 0; i < 8; i++) {
		    EGTrecords.parseData(EGTrecords.extractRecordData(in));
		}
	    } else if (nextType == Type.NAM3) {
		subRecords.importSubRecord(in); // import NAM3
		for (int i = 0; i < 6; i++) {
		    HKXrecords.parseData(HKXrecords.extractRecordData(in));
		}
	    } else if (nextType == Type.NAM0) {
		subRecords.importSubRecord(in); // import NAM0
		while (!in.isDone() && getNextType(in) != Type.WKMV) {
		    headData.parseData(headData.extractRecordData(in));
		}
	    } else {
		subRecords.importSubRecord(in);
	    }
	}
    }

    static class MFNAMdata extends SubShell {

	SubString ANAM = new SubString(Type.ANAM, true);
	SubData MODT = new SubData(Type.MODT);
	private static Type[] types = {Type.ANAM, Type.MODT};

	public MFNAMdata() {
	    super(types);
	    subRecords.add(ANAM);
	    subRecords.add(MODT);
	}

	@Override
	SubRecord getNew(Type type) {
	    return new MFNAMdata();
	}
        
        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final MFNAMdata other = (MFNAMdata) obj;
            if (!Objects.equals(this.ANAM, other.ANAM)) {
                return false;
            }
            if (!Objects.equals(this.MODT, other.MODT)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 3;
            hash = 53 * hash + Objects.hashCode(this.ANAM);
            hash = 53 * hash + Objects.hashCode(this.MODT);
            return hash;
        }
    }

    static class ATKDpackage extends SubShell {

	SubData ATKD = new SubData(Type.ATKD);
	SubString ATKE = new SubString(Type.ATKE, true);
	private static Type[] types = {Type.ATKD, Type.ATKE};

	public ATKDpackage() {
	    super(types);
	    subRecords.add(ATKD);
	    subRecords.add(ATKE);
	}

	@Override
	SubRecord getNew(Type type) {
	    return new ATKDpackage();
	}
        
        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final ATKDpackage other = (ATKDpackage) obj;
            if (!Objects.equals(this.ATKD, other.ATKD)) {
                return false;
            }
            if (!Objects.equals(this.ATKE, other.ATKE)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 5;
            hash = 29 * hash + Objects.hashCode(this.ATKD);
            hash = 29 * hash + Objects.hashCode(this.ATKE);
            return hash;
        }
    }

    static class EGTmodel extends SubShell {

	SubData INDX = new SubData(Type.INDX);
	SubString MODL = new SubString(Type.MODL, true);
	SubData MODT = new SubData(Type.MODT);
	private static Type[] types = {Type.INDX};

	public EGTmodel() {
	    super(types);
	    subRecords.add(INDX);
	    subRecords.add(MODL);
	    subRecords.add(MODT);
	}

	@Override
	SubRecord getNew(Type type) {
	    return new EGTmodel();
	}
        
        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final EGTmodel other = (EGTmodel) obj;
            if (!Objects.equals(this.INDX, other.INDX)) {
                return false;
            }
            if (!Objects.equals(this.MODL, other.MODL)) {
                return false;
            }
            if (!Objects.equals(this.MODT, other.MODT)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 17 * hash + Objects.hashCode(this.INDX);
            hash = 17 * hash + Objects.hashCode(this.MODL);
            hash = 17 * hash + Objects.hashCode(this.MODT);
            return hash;
        }
    }

    static class HKXmodel extends SubShell {

	SubString MODL = new SubString(Type.MODL, true);
	SubData MODT = new SubData(Type.MODT);
	private static Type[] types = {};

	public HKXmodel() {
	    super(types);
	    subRecords.add(MODL);
	    subRecords.add(MODT);
	}

	@Override
	SubRecord getNew(Type type) {
	    return new HKXmodel();
	}
        
        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final HKXmodel other = (HKXmodel) obj;
            if (!Objects.equals(this.MODL, other.MODL)) {
                return false;
            }
            if (!Objects.equals(this.MODT, other.MODT)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 89 * hash + Objects.hashCode(this.MODL);
            hash = 89 * hash + Objects.hashCode(this.MODT);
            return hash;
        }
    }

    static class MTYPpackage extends SubShell {

	SubForm MTYP = new SubForm(Type.MTYP);
	SubData SPED = new SubData(Type.SPED);
	private static Type[] types = {Type.MTYP, Type.SPED};

	public MTYPpackage() {
	    super(types);
	    subRecords.add(MTYP);
	    subRecords.add(SPED);
	}

	@Override
	SubRecord getNew(Type type) {
	    return new MTYPpackage();
	}
        
        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final MTYPpackage other = (MTYPpackage) obj;
            if (!Objects.equals(this.MTYP, other.MTYP)) {
                return false;
            }
            if (!Objects.equals(this.SPED, other.SPED)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 59 * hash + Objects.hashCode(this.MTYP);
            hash = 59 * hash + Objects.hashCode(this.SPED);
            return hash;
        }
    }

    static class HeadData extends SubShell {

	private static Type[] types = {Type.NAM0};
	SubData NAM0 = new SubData(Type.NAM0);
	SubData MNAM = new SubData(Type.MNAM);
	SubData FNAM = new SubData(Type.FNAM);
	SubList<HEADs> INDXs = new SubList<HEADs>(new HEADs());
	SubList<MPAVs> MPAVs = new SubList<MPAVs>(new MPAVs());
	SubList<SubForm> RPRM = new SubList<SubForm>(new SubForm(Type.RPRM));
	SubList<SubForm> RPRF = new SubList<SubForm>(new SubForm(Type.RPRF));
	SubList<SubForm> AHCM = new SubList<SubForm>(new SubForm(Type.AHCM));
	SubList<SubForm> AHCF = new SubList<SubForm>(new SubForm(Type.AHCF));
	SubList<SubForm> FTSM = new SubList<SubForm>(new SubForm(Type.FTSM));
	SubList<SubForm> FTSF = new SubList<SubForm>(new SubForm(Type.FTSF));
	SubList<SubForm> DFTM = new SubList<SubForm>(new SubForm(Type.DFTM));
	SubList<SubForm> DFTF = new SubList<SubForm>(new SubForm(Type.DFTF));
	SubList<TINIs> TINIs = new SubList<TINIs>(new TINIs());
	SubForm NAM8 = new SubForm(Type.NAM8);
	SubForm RNAM = new SubForm(Type.RNAM);

	public HeadData() {
	    super(types);
	    subRecords.add(NAM0);
	    subRecords.add(MNAM);
	    subRecords.add(FNAM);
	    subRecords.add(INDXs);
	    subRecords.add(MPAVs);
	    subRecords.add(RPRM);
	    subRecords.add(RPRF);
	    subRecords.add(AHCM);
	    subRecords.add(AHCF);
	    subRecords.add(FTSM);
	    subRecords.add(FTSF);
	    subRecords.add(DFTM);
	    subRecords.add(DFTF);
	    subRecords.add(TINIs);
	    subRecords.add(NAM8);
	    subRecords.add(RNAM);
	}

	@Override
	SubRecord getNew(Type type) {
	    return new HeadData();
	}

	@Override
	Boolean isValid() {
	    return true;
	}
        
        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final HeadData other = (HeadData) obj;
            if (!Objects.equals(this.NAM0, other.NAM0)) {
                return false;
            }
            if (!Objects.equals(this.MNAM, other.MNAM)) {
                return false;
            }
            if (!Objects.equals(this.FNAM, other.FNAM)) {
                return false;
            }
            if (!Objects.equals(this.INDXs, other.INDXs)) {
                return false;
            }
            if (!Objects.equals(this.MPAVs, other.MPAVs)) {
                return false;
            }
            if (!Objects.equals(this.RPRM, other.RPRM)) {
                return false;
            }
            if (!Objects.equals(this.RPRF, other.RPRF)) {
                return false;
            }
            if (!Objects.equals(this.AHCM, other.AHCM)) {
                return false;
            }
            if (!Objects.equals(this.AHCF, other.AHCF)) {
                return false;
            }
            if (!Objects.equals(this.FTSM, other.FTSM)) {
                return false;
            }
            if (!Objects.equals(this.FTSF, other.FTSF)) {
                return false;
            }
            if (!Objects.equals(this.DFTM, other.DFTM)) {
                return false;
            }
            if (!Objects.equals(this.DFTF, other.DFTF)) {
                return false;
            }
            if (!Objects.equals(this.TINIs, other.TINIs)) {
                return false;
            }
            if (!Objects.equals(this.NAM8, other.NAM8)) {
                return false;
            }
            if (!Objects.equals(this.RNAM, other.RNAM)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 53 * hash + Objects.hashCode(this.NAM0);
            hash = 53 * hash + Objects.hashCode(this.MNAM);
            hash = 53 * hash + Objects.hashCode(this.FNAM);
            hash = 53 * hash + Objects.hashCode(this.INDXs);
            hash = 53 * hash + Objects.hashCode(this.MPAVs);
            hash = 53 * hash + Objects.hashCode(this.RPRM);
            hash = 53 * hash + Objects.hashCode(this.RPRF);
            hash = 53 * hash + Objects.hashCode(this.AHCM);
            hash = 53 * hash + Objects.hashCode(this.AHCF);
            hash = 53 * hash + Objects.hashCode(this.FTSM);
            hash = 53 * hash + Objects.hashCode(this.FTSF);
            hash = 53 * hash + Objects.hashCode(this.DFTM);
            hash = 53 * hash + Objects.hashCode(this.DFTF);
            hash = 53 * hash + Objects.hashCode(this.TINIs);
            hash = 53 * hash + Objects.hashCode(this.NAM8);
            hash = 53 * hash + Objects.hashCode(this.RNAM);
            return hash;
        }
    }

    static class HEADs extends SubShell {

	SubData INDX = new SubData(Type.INDX);
	SubData HEAD = new SubData(Type.HEAD);
	private static Type[] types = {Type.INDX, Type.HEAD};

	public HEADs() {
	    super(types);
	    subRecords.add(INDX);
	    subRecords.add(HEAD);
	}

	@Override
	SubRecord getNew(Type type) {
	    return new HEADs();
	}

	@Override
	Boolean isValid() {
	    return true;
	}
        
        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final HEADs other = (HEADs) obj;
            if (!Objects.equals(this.INDX, other.INDX)) {
                return false;
            }
            if (!Objects.equals(this.HEAD, other.HEAD)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 3;
            hash = 37 * hash + Objects.hashCode(this.INDX);
            hash = 37 * hash + Objects.hashCode(this.HEAD);
            return hash;
        }
    }

    static class MPAVs extends SubShell {

	SubData MPAI = new SubData(Type.MPAI);
	SubData MPAV = new SubData(Type.MPAV);
	private static Type[] types = {Type.MPAI, Type.MPAV};

	public MPAVs() {
	    super(types);
	    subRecords.add(MPAI);
	    subRecords.add(MPAV);
	}

	@Override
	SubRecord getNew(Type type) {
	    return new MPAVs();
	}

	@Override
	Boolean isValid() {
	    return true;
	}
        
        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final MPAVs other = (MPAVs) obj;
            if (!Objects.equals(this.MPAI, other.MPAI)) {
                return false;
            }
            if (!Objects.equals(this.MPAV, other.MPAV)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 3;
            hash = 37 * hash + Objects.hashCode(this.MPAI);
            hash = 37 * hash + Objects.hashCode(this.MPAV);
            return hash;
        }
    }

    static class TINIs extends SubShell {

	SubData TINI = new SubData(Type.TINI);
	SubString TINT = new SubString(Type.TINT, true);
	SubData TINP = new SubData(Type.TINP);
	SubForm TIND = new SubForm(Type.TIND);
	SubList<TINCs> TINCs = new SubList<TINCs>(new TINCs());
	private static Type[] types = {Type.TINI, Type.TINT, Type.TINP, Type.TIND, Type.TINC, Type.TINV, Type.TIRS};

	public TINIs() {
	    super(types);
	    subRecords.add(TINI);
	    subRecords.add(TINT);
	    subRecords.add(TINP);
	    subRecords.add(TIND);
	    subRecords.add(TINCs);
	}

	@Override
	SubRecord getNew(Type type) {
	    return new TINIs();
	}

	@Override
	Boolean isValid() {
	    return true;
	}
        
        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final TINIs other = (TINIs) obj;
            if (!Objects.equals(this.TINI, other.TINI)) {
                return false;
            }
            if (!Objects.equals(this.TINT, other.TINT)) {
                return false;
            }
            if (!Objects.equals(this.TINP, other.TINP)) {
                return false;
            }
            if (!Objects.equals(this.TIND, other.TIND)) {
                return false;
            }
            if (!Objects.equals(this.TINCs, other.TINCs)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 67 * hash + Objects.hashCode(this.TINI);
            hash = 67 * hash + Objects.hashCode(this.TINT);
            hash = 67 * hash + Objects.hashCode(this.TINP);
            hash = 67 * hash + Objects.hashCode(this.TIND);
            hash = 67 * hash + Objects.hashCode(this.TINCs);
            return hash;
        }
    }

    static class TINCs extends SubShell {

	SubData TINC = new SubData(Type.TINC);
	SubData TINV = new SubData(Type.TINV);
	SubData TIRS = new SubData(Type.TIRS);
	private static Type[] types = {Type.TINC, Type.TINV, Type.TIRS};

	public TINCs() {
	    super(types);
	    subRecords.add(TINC);
	    subRecords.add(TINV);
	    subRecords.add(TIRS);
	}

	@Override
	SubRecord getNew(Type type) {
	    return new TINCs();
	}

	@Override
	Boolean isValid() {
	    return true;
	}
        
        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final TINCs other = (TINCs) obj;
            if (!Objects.equals(this.TINC, other.TINC)) {
                return false;
            }
            if (!Objects.equals(this.TINV, other.TINV)) {
                return false;
            }
            if (!Objects.equals(this.TIRS, other.TIRS)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 29 * hash + Objects.hashCode(this.TINC);
            hash = 29 * hash + Objects.hashCode(this.TINV);
            hash = 29 * hash + Objects.hashCode(this.TIRS);
            return hash;
        }
    }

    static class DATA extends SubRecord {

	byte[] fluff1 = new byte[16];
	float maleHeight = 0;
	float femaleHeight = 0;
	float maleWeight = 0;
	float femaleWeight = 0;
	LFlags flags = new LFlags(4);
	float startingHealth = 0;
	float startingMagicka = 0;
	float startingStamina = 0;
	float baseCarryWeight = 0;
	float baseMass = 0;
	float accelerationRate = 0;
	float decelerationRate = 0;
	Size size = Size.MEDIUM;
	byte[] fluff3 = new byte[8];
	float injuredHealthPct = 0;
	byte[] fluff4 = new byte[4];
	float healthRegen = 0;
	float magickaRegen = 0;
	float staminaRegen = 0;
	float unarmedDamage = 0;
	float unarmedReach = 0;
	byte[] fluff5 = new byte[4];
	float aimAngleTolerance = 0;
	float flightRadius = 0;
	float angularAcceleration = 0;
	float angularTolerance = 0;
	byte[] fluff6 = new byte[4];

	DATA() {
	    super(Type.DATA);
	}

	@Override
	void export(LExporter out, Mod srcMod) throws IOException {
	    super.export(out, srcMod);
	    out.write(fluff1, 16);
	    out.write(maleHeight);
	    out.write(femaleHeight);
	    out.write(maleWeight);
	    out.write(femaleWeight);
	    out.write(flags.export(), 4);
	    out.write(startingHealth);
	    out.write(startingMagicka);
	    out.write(startingStamina);
	    out.write(baseCarryWeight);
	    out.write(baseMass);
	    out.write(accelerationRate);
	    out.write(decelerationRate);
	    out.write(size.ordinal(), 4);
	    out.write(fluff3, 8);
	    out.write(injuredHealthPct);
	    out.write(fluff4, 4);
	    out.write(healthRegen);
	    out.write(magickaRegen);
	    out.write(staminaRegen);
	    out.write(unarmedDamage);
	    out.write(unarmedReach);
	    out.write(fluff5, 4);
	    out.write(aimAngleTolerance);
	    out.write(flightRadius);
	    out.write(angularAcceleration);
	    out.write(angularTolerance);
	    out.write(fluff6, 4);
	}

	@Override
	void parseData(LStream in) throws BadRecord, DataFormatException, BadParameter, IOException {
	    super.parseData(in);
	    fluff1 = in.extract(16);
	    maleHeight = in.extractFloat();
	    femaleHeight = in.extractFloat();
	    maleWeight = in.extractFloat();
	    femaleWeight = in.extractFloat();
	    flags.set(in.extract(4));
	    startingHealth = in.extractFloat();
	    startingMagicka = in.extractFloat();
	    startingStamina = in.extractFloat();
	    baseCarryWeight = in.extractFloat();
	    baseMass = in.extractFloat();
	    accelerationRate = in.extractFloat();
	    decelerationRate = in.extractFloat();
	    size = Size.values()[in.extractInt(4)];
	    fluff3 = in.extract(8);
	    injuredHealthPct = in.extractFloat();
	    fluff4 = in.extract(4);
	    healthRegen = in.extractFloat();
	    magickaRegen = in.extractFloat();
	    staminaRegen = in.extractFloat();
	    unarmedDamage = in.extractFloat();
	    unarmedReach = in.extractFloat();
	    fluff5 = in.extract(4);
	    aimAngleTolerance = in.extractFloat();
	    flightRadius = in.extractFloat();
	    angularAcceleration = in.extractFloat();
	    angularTolerance = in.extractFloat();
	    fluff6 = in.extract(4);
	}

	@Override
	SubRecord getNew(Type type) {
	    return new DATA();
	}

	@Override
	int getContentLength(Mod srcMod) {
	    return 128;
	}

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final DATA other = (DATA) obj;
            if (!Arrays.equals(this.fluff1, other.fluff1)) {
                return false;
            }
            if (Float.floatToIntBits(this.maleHeight) != Float.floatToIntBits(other.maleHeight)) {
                return false;
            }
            if (Float.floatToIntBits(this.femaleHeight) != Float.floatToIntBits(other.femaleHeight)) {
                return false;
            }
            if (Float.floatToIntBits(this.maleWeight) != Float.floatToIntBits(other.maleWeight)) {
                return false;
            }
            if (Float.floatToIntBits(this.femaleWeight) != Float.floatToIntBits(other.femaleWeight)) {
                return false;
            }
            if (!Objects.equals(this.flags, other.flags)) {
                return false;
            }
            if (Float.floatToIntBits(this.startingHealth) != Float.floatToIntBits(other.startingHealth)) {
                return false;
            }
            if (Float.floatToIntBits(this.startingMagicka) != Float.floatToIntBits(other.startingMagicka)) {
                return false;
            }
            if (Float.floatToIntBits(this.startingStamina) != Float.floatToIntBits(other.startingStamina)) {
                return false;
            }
            if (Float.floatToIntBits(this.baseCarryWeight) != Float.floatToIntBits(other.baseCarryWeight)) {
                return false;
            }
            if (Float.floatToIntBits(this.baseMass) != Float.floatToIntBits(other.baseMass)) {
                return false;
            }
            if (Float.floatToIntBits(this.accelerationRate) != Float.floatToIntBits(other.accelerationRate)) {
                return false;
            }
            if (Float.floatToIntBits(this.decelerationRate) != Float.floatToIntBits(other.decelerationRate)) {
                return false;
            }
            if (this.size != other.size) {
                return false;
            }
            if (!Arrays.equals(this.fluff3, other.fluff3)) {
                return false;
            }
            if (Float.floatToIntBits(this.injuredHealthPct) != Float.floatToIntBits(other.injuredHealthPct)) {
                return false;
            }
            if (!Arrays.equals(this.fluff4, other.fluff4)) {
                return false;
            }
            if (Float.floatToIntBits(this.healthRegen) != Float.floatToIntBits(other.healthRegen)) {
                return false;
            }
            if (Float.floatToIntBits(this.magickaRegen) != Float.floatToIntBits(other.magickaRegen)) {
                return false;
            }
            if (Float.floatToIntBits(this.staminaRegen) != Float.floatToIntBits(other.staminaRegen)) {
                return false;
            }
            if (Float.floatToIntBits(this.unarmedDamage) != Float.floatToIntBits(other.unarmedDamage)) {
                return false;
            }
            if (Float.floatToIntBits(this.unarmedReach) != Float.floatToIntBits(other.unarmedReach)) {
                return false;
            }
            if (!Arrays.equals(this.fluff5, other.fluff5)) {
                return false;
            }
            if (Float.floatToIntBits(this.aimAngleTolerance) != Float.floatToIntBits(other.aimAngleTolerance)) {
                return false;
            }
            if (Float.floatToIntBits(this.flightRadius) != Float.floatToIntBits(other.flightRadius)) {
                return false;
            }
            if (Float.floatToIntBits(this.angularAcceleration) != Float.floatToIntBits(other.angularAcceleration)) {
                return false;
            }
            if (Float.floatToIntBits(this.angularTolerance) != Float.floatToIntBits(other.angularTolerance)) {
                return false;
            }
            if (!Arrays.equals(this.fluff6, other.fluff6)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 73 * hash + Arrays.hashCode(this.fluff1);
            hash = 73 * hash + Float.floatToIntBits(this.maleHeight);
            hash = 73 * hash + Float.floatToIntBits(this.femaleHeight);
            hash = 73 * hash + Float.floatToIntBits(this.maleWeight);
            hash = 73 * hash + Float.floatToIntBits(this.femaleWeight);
            hash = 73 * hash + Objects.hashCode(this.flags);
            hash = 73 * hash + Float.floatToIntBits(this.startingHealth);
            hash = 73 * hash + Float.floatToIntBits(this.startingMagicka);
            hash = 73 * hash + Float.floatToIntBits(this.startingStamina);
            hash = 73 * hash + Float.floatToIntBits(this.baseCarryWeight);
            hash = 73 * hash + Float.floatToIntBits(this.baseMass);
            hash = 73 * hash + Float.floatToIntBits(this.accelerationRate);
            hash = 73 * hash + Float.floatToIntBits(this.decelerationRate);
            hash = 73 * hash + (this.size != null ? this.size.hashCode() : 0);
            hash = 73 * hash + Arrays.hashCode(this.fluff3);
            hash = 73 * hash + Float.floatToIntBits(this.injuredHealthPct);
            hash = 73 * hash + Arrays.hashCode(this.fluff4);
            hash = 73 * hash + Float.floatToIntBits(this.healthRegen);
            hash = 73 * hash + Float.floatToIntBits(this.magickaRegen);
            hash = 73 * hash + Float.floatToIntBits(this.staminaRegen);
            hash = 73 * hash + Float.floatToIntBits(this.unarmedDamage);
            hash = 73 * hash + Float.floatToIntBits(this.unarmedReach);
            hash = 73 * hash + Arrays.hashCode(this.fluff5);
            hash = 73 * hash + Float.floatToIntBits(this.aimAngleTolerance);
            hash = 73 * hash + Float.floatToIntBits(this.flightRadius);
            hash = 73 * hash + Float.floatToIntBits(this.angularAcceleration);
            hash = 73 * hash + Float.floatToIntBits(this.angularTolerance);
            hash = 73 * hash + Arrays.hashCode(this.fluff6);
            return hash;
        }
        

        @Override
        public SubRecord merge(SubRecord no, SubRecord bo) {
            DATA d = this;
            if (!(no == null && bo == null && (no instanceof DATA) && (bo instanceof DATA))) {
                final DATA nd = (DATA) no;
                final DATA bd = (DATA) bo;
                SkyBash.merge(d.accelerationRate, nd.accelerationRate, bd.accelerationRate, type[0], "acceleration rate");
                SkyBash.merge(d.fluff1, nd.fluff1, bd.fluff1, type[0], "unknown");
                SkyBash.merge(d.femaleHeight, nd.femaleHeight, bd.femaleHeight, type[0], "female height");
                SkyBash.merge(d.maleHeight, nd.maleHeight, bd.maleHeight, type[0], "male height");
                SkyBash.merge(d.maleWeight, nd.maleWeight, bd.maleWeight, type[0], "male weight");
                SkyBash.merge(d.femaleWeight, nd.femaleWeight, bd.femaleWeight, type[0], "female weight");
                SkyBash.merge(d.fluff3, nd.fluff3, bd.fluff3, type[0], "unknown");
                SkyBash.merge(d.startingHealth, nd.startingHealth, bd.startingHealth, type[0], "starting health");
                SkyBash.merge(d.startingMagicka, nd.startingMagicka, bd.startingMagicka, type[0], "starting magicka");
                SkyBash.merge(d.startingStamina, nd.startingStamina, bd.startingStamina, type[0], "starting stamina");
                SkyBash.merge(d.baseCarryWeight, nd.baseCarryWeight, bd.baseCarryWeight, type[0], "base carry weight");
                SkyBash.merge(d.baseMass, nd.baseMass, bd.baseMass, type[0], "base mass");
                SkyBash.merge(d.decelerationRate, nd.decelerationRate, bd.decelerationRate, type[0], "deceleration rate");
                SkyBash.merge(d.size, nd.size, bd.size, type[0], "size");
                d.flags.merge(nd.flags, bd.flags);
                SkyBash.merge(d.injuredHealthPct, nd.injuredHealthPct, bd.injuredHealthPct, type[0], "injured health percentage");
                SkyBash.merge(d.fluff4, nd.fluff4, bd.fluff4, type[0], "unknown");
                SkyBash.merge(d.healthRegen, nd.healthRegen, bd.healthRegen, type[0], "health regen");
                SkyBash.merge(d.magickaRegen, nd.magickaRegen, bd.magickaRegen, type[0], "magicka regen");
                SkyBash.merge(d.staminaRegen, nd.staminaRegen, bd.staminaRegen, type[0], "stamina regen");
                SkyBash.merge(d.unarmedDamage, nd.unarmedDamage, bd.unarmedDamage, type[0], "unarmed damage");
                SkyBash.merge(d.unarmedReach, nd.unarmedReach, bd.unarmedReach, type[0], "unarmed reach");
                SkyBash.merge(d.fluff5, nd.fluff5, bd.fluff5, type[0], "unknown");
                SkyBash.merge(d.aimAngleTolerance, nd.aimAngleTolerance, bd.aimAngleTolerance, type[0], "aim angle tolerance");
                SkyBash.merge(d.flightRadius, nd.flightRadius, bd.flightRadius, type[0], "flight radius");
                SkyBash.merge(d.angularAcceleration, nd.angularAcceleration, bd.angularAcceleration, type[0], "angular acceleration");
                SkyBash.merge(d.angularTolerance, nd.angularTolerance, bd.angularTolerance, type[0], "angular tolerance");
                SkyBash.merge(d.fluff6, nd.fluff6, bd.fluff6, type[0], "unknown");
            }
            return d;
        }
    }

    public static enum RACEFlags {

	Playable,
	FaceGenHead,
	Child,
	TiltFrontBack,
	TiltLeftRight,
	NoShadow,
	Swims,
	Flies,
	Walks,
	Immobile,
	NotPushable,
	NoCombatInWater,
	NoRotatingToHeadTrack,
	DontShowBloodSpray,
	DontShowBloodDecal,
	UsesHeadTrackAnims,
	SpellsAlignWithMagicNode,
	UseWorldRaycastsForFootIK,
	AllowRagdollCollision,
	RegenHPInCombat,
	CantOpenDoors,
	AllowPCDialogue,
	NoKnockdowns,
	AllowPickpocket,
	AlwaysUseProxyController,
	DontShowWeaponBlood,
	OverlayHeadPartList,
	OverrideHeadPartList,
	CanPickupItems,
	AllowMultipleMembraneShaders,
	CanDualWeild,
	AvoidsRoads;
    }

    /**
     *
     */
    public enum Size {

	/**
	 *
	 */
	SMALL,
	/**
	 *
	 */
	MEDIUM,
	/**
	 *
	 */
	LARGE,
	/**
	 *
	 */
	EXTRALARGE,}
    
    //Generics
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final RACE other = (RACE) obj;
        if (!Objects.equals(this.spells, other.spells)) {
            return false;
        }
        if (!Objects.equals(this.WNAM, other.WNAM)) {
            return false;
        }
        if (!Objects.equals(this.bodyTemplate, other.bodyTemplate)) {
            return false;
        }
        if (!Objects.equals(this.keywords, other.keywords)) {
            return false;
        }
        if (!Objects.equals(this.DATA, other.DATA)) {
            return false;
        }
        if (!Objects.equals(this.MFNAM, other.MFNAM)) {
            return false;
        }
        if (!Objects.equals(this.MTNMs, other.MTNMs)) {
            return false;
        }
        if (!Objects.equals(this.VTCK, other.VTCK)) {
            return false;
        }
        if (!Objects.equals(this.DNAM, other.DNAM)) {
            return false;
        }
        if (!Objects.equals(this.HCLF, other.HCLF)) {
            return false;
        }
        if (!Objects.equals(this.TINL, other.TINL)) {
            return false;
        }
        if (!Objects.equals(this.PNAM, other.PNAM)) {
            return false;
        }
        if (!Objects.equals(this.UNAM, other.UNAM)) {
            return false;
        }
        if (!Objects.equals(this.ATKR, other.ATKR)) {
            return false;
        }
        if (!Objects.equals(this.ATKDs, other.ATKDs)) {
            return false;
        }
        if (!Objects.equals(this.NAM1, other.NAM1)) {
            return false;
        }
        if (!Objects.equals(this.EGTrecords, other.EGTrecords)) {
            return false;
        }
        if (!Objects.equals(this.GNAM, other.GNAM)) {
            return false;
        }
        if (!Objects.equals(this.NAM3, other.NAM3)) {
            return false;
        }
        if (!Objects.equals(this.HKXrecords, other.HKXrecords)) {
            return false;
        }
        if (!Objects.equals(this.NAM4, other.NAM4)) {
            return false;
        }
        if (!Objects.equals(this.NAM5, other.NAM5)) {
            return false;
        }
        if (!Objects.equals(this.NAM7, other.NAM7)) {
            return false;
        }
        if (!Objects.equals(this.ONAM, other.ONAM)) {
            return false;
        }
        if (!Objects.equals(this.LNAM, other.LNAM)) {
            return false;
        }
        if (!Objects.equals(this.NAMEs, other.NAMEs)) {
            return false;
        }
        if (!Objects.equals(this.MTYPs, other.MTYPs)) {
            return false;
        }
        if (!Objects.equals(this.VNAM, other.VNAM)) {
            return false;
        }
        if (!Objects.equals(this.QNAM, other.QNAM)) {
            return false;
        }
        if (!Objects.equals(this.UNES, other.UNES)) {
            return false;
        }
        if (!Objects.equals(this.PHTN, other.PHTN)) {
            return false;
        }
        if (!Objects.equals(this.PHWT, other.PHWT)) {
            return false;
        }
        if (!Objects.equals(this.headData, other.headData)) {
            return false;
        }
        if (!Objects.equals(this.NAM8, other.NAM8)) {
            return false;
        }
        if (!Objects.equals(this.RNAM, other.RNAM)) {
            return false;
        }
        if (!Objects.equals(this.WKMV, other.WKMV)) {
            return false;
        }
        if (!Objects.equals(this.RNMV, other.RNMV)) {
            return false;
        }
        if (!Objects.equals(this.SWMV, other.SWMV)) {
            return false;
        }
        if (!Objects.equals(this.FLMV, other.FLMV)) {
            return false;
        }
        if (!Objects.equals(this.SNMV, other.SNMV)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 41 * hash + Objects.hashCode(this.spells);
        hash = 41 * hash + Objects.hashCode(this.WNAM);
        hash = 41 * hash + Objects.hashCode(this.bodyTemplate);
        hash = 41 * hash + Objects.hashCode(this.keywords);
        hash = 41 * hash + Objects.hashCode(this.DATA);
        hash = 41 * hash + Objects.hashCode(this.MFNAM);
        hash = 41 * hash + Objects.hashCode(this.MTNMs);
        hash = 41 * hash + Objects.hashCode(this.VTCK);
        hash = 41 * hash + Objects.hashCode(this.DNAM);
        hash = 41 * hash + Objects.hashCode(this.HCLF);
        hash = 41 * hash + Objects.hashCode(this.TINL);
        hash = 41 * hash + Objects.hashCode(this.PNAM);
        hash = 41 * hash + Objects.hashCode(this.UNAM);
        hash = 41 * hash + Objects.hashCode(this.ATKR);
        hash = 41 * hash + Objects.hashCode(this.ATKDs);
        hash = 41 * hash + Objects.hashCode(this.NAM1);
        hash = 41 * hash + Objects.hashCode(this.EGTrecords);
        hash = 41 * hash + Objects.hashCode(this.GNAM);
        hash = 41 * hash + Objects.hashCode(this.NAM3);
        hash = 41 * hash + Objects.hashCode(this.HKXrecords);
        hash = 41 * hash + Objects.hashCode(this.NAM4);
        hash = 41 * hash + Objects.hashCode(this.NAM5);
        hash = 41 * hash + Objects.hashCode(this.NAM7);
        hash = 41 * hash + Objects.hashCode(this.ONAM);
        hash = 41 * hash + Objects.hashCode(this.LNAM);
        hash = 41 * hash + Objects.hashCode(this.NAMEs);
        hash = 41 * hash + Objects.hashCode(this.MTYPs);
        hash = 41 * hash + Objects.hashCode(this.VNAM);
        hash = 41 * hash + Objects.hashCode(this.QNAM);
        hash = 41 * hash + Objects.hashCode(this.UNES);
        hash = 41 * hash + Objects.hashCode(this.PHTN);
        hash = 41 * hash + Objects.hashCode(this.PHWT);
        hash = 41 * hash + Objects.hashCode(this.headData);
        hash = 41 * hash + Objects.hashCode(this.NAM8);
        hash = 41 * hash + Objects.hashCode(this.RNAM);
        hash = 41 * hash + Objects.hashCode(this.WKMV);
        hash = 41 * hash + Objects.hashCode(this.RNMV);
        hash = 41 * hash + Objects.hashCode(this.SWMV);
        hash = 41 * hash + Objects.hashCode(this.FLMV);
        hash = 41 * hash + Objects.hashCode(this.SNMV);
        return hash;
    }

    @Override
    public MajorRecord merge(MajorRecord no, MajorRecord bo) {
        super.merge(no, bo);
        RACE r = this;
        if (!(no == null && bo == null && (no instanceof RACE) && (bo instanceof RACE))) {
            final RACE nr = (RACE) no;
            final RACE br = (RACE) bo;
            SubRecords sList = r.subRecords;
            SubRecords nsList = nr.subRecords;
            SubRecords bsList = br.subRecords;
            for (SubRecord s : sList) {
                s.merge(nsList.get(s.type[0]), bsList.get(s.type[0]));
            }
        }
        return r;
    }

    // Get / set
    public void set(RACEFlags flag, boolean on) {
	DATA.flags.set(flag.ordinal(), on);
    }

    public boolean get(RACEFlags flag) {
	return DATA.flags.get(flag.ordinal());
    }

    /**
     *
     * @return FormID of the ARMO record that is worn.
     */
    public FormID getWornArmor() {
	return WNAM.getForm();
    }

    /**
     *
     * @param id FormID to set the worn ARMO record to.
     */
    public void setWornArmor(FormID id) {
	WNAM.setForm(id);
    }

    /**
     *
     * @return
     */
    public ArrayList<FormID> getSpells() {
	return SubList.subFormToPublic(spells);
    }

    /**
     *
     * @param spell
     */
    public void addSpell(FormID spell) {
	spells.add(new SubForm(Type.SPLO, spell));
    }

    /**
     *
     * @param spell
     */
    public void removeSpell(FormID spell) {
	spells.remove(new SubForm(Type.SPLO, spell));
    }

    /**
     *
     */
    public void clearSpells() {
	spells.clear();
    }

    /**
     *
     * @param gender
     * @param model
     */
    public void setModel(Gender gender, String model) {
	switch (gender) {
	    case MALE:
		if (!MFNAM.set.containsKey(Type.MNAM)) {
		    MFNAM.set.put(Type.MNAM, new MFNAMdata());
		}
		MFNAM.set.get(Type.MNAM).ANAM.setString(model);
		break;
	    default:
		if (!MFNAM.set.containsKey(Type.FNAM)) {
		    MFNAM.set.put(Type.FNAM, new MFNAMdata());
		}
		MFNAM.set.get(Type.FNAM).ANAM.setString(model);
		break;
	}
    }

    /**
     *
     * @param gender
     * @return
     */
    public String getModel(Gender gender) {
	switch (gender) {
	    case MALE:
		if (MFNAM.set.containsKey(Type.MNAM)) {
		    return MFNAM.set.get(Type.MNAM).ANAM.string;
		}
		break;
	    case FEMALE:
		if (MFNAM.set.containsKey(Type.FNAM)) {
		    return MFNAM.set.get(Type.FNAM).ANAM.string;
		}
		break;
	}
	return "";
    }

    /**
     *
     * @param gender
     * @param voice
     */
    public void setVoiceType(Gender gender, FormID voice) {
	switch (gender) {
	    case MALE:
		VTCK.IDs.set(0, voice);
		break;
	    default:
		VTCK.IDs.set(1, voice);
		break;
	}
    }

    /**
     *
     * @param gender
     * @return
     */
    public FormID getVoiceType(Gender gender) {
	switch (gender) {
	    case MALE:
		return VTCK.IDs.get(0);
	    default:
		return VTCK.IDs.get(1);
	}
    }

    /**
     *
     * @param gender
     * @param color
     */
    public void setHairColor(Gender gender, FormID color) {
	switch (gender) {
	    case MALE:
		HCLF.IDs.set(0, color);
		break;
	    default:
		HCLF.IDs.set(1, color);
		break;
	}
    }

    /**
     *
     * @param gender
     * @return
     */
    public FormID getHairColor(Gender gender) {
	switch (gender) {
	    case MALE:
		return HCLF.IDs.get(0);
	    default:
		return HCLF.IDs.get(1);
	}
    }

    /**
     *
     * @param gender
     * @param part
     */
    public void setDecapHeadPart(Gender gender, FormID part) {
	switch (gender) {
	    case MALE:
		DNAM.IDs.set(0, part);
		break;
	    default:
		DNAM.IDs.set(1, part);
		break;
	}
    }

    /**
     *
     * @param gender
     * @return
     */
    public FormID getDecapHeadPart(Gender gender) {
	switch (gender) {
	    case MALE:
		return DNAM.IDs.get(0);
	    default:
		return DNAM.IDs.get(1);
	}
    }

    /**
     *
     * @param gender
     * @param value
     */
    public void setHeight(Gender gender, float value) {
	switch (gender) {
	    case MALE:
		DATA.maleHeight = value;
	    case FEMALE:
		DATA.femaleHeight = value;
	}
    }

    /**
     *
     * @param gender
     * @return
     */
    public float getHeight(Gender gender) {
	switch (gender) {
	    case MALE:
		return DATA.maleHeight;
	    default:
		return DATA.femaleHeight;
	}
    }

    /**
     *
     * @return
     */
    public float getAccelerationRate() {
	return DATA.accelerationRate;
    }

    /**
     *
     * @param accelerationRate
     */
    public void setAccelerationRate(float accelerationRate) {
	this.DATA.accelerationRate = accelerationRate;
    }

    /**
     *
     * @return
     */
    public float getAimAngleTolerance() {
	return DATA.aimAngleTolerance;
    }

    /**
     *
     * @param aimAngleTolerance
     */
    public void setAimAngleTolerance(float aimAngleTolerance) {
	this.DATA.aimAngleTolerance = aimAngleTolerance;
    }

    /**
     *
     * @return
     */
    public float getAngularAcceleration() {
	return DATA.angularAcceleration;
    }

    /**
     *
     * @param angularAcceleration
     */
    public void setAngularAcceleration(float angularAcceleration) {
	this.DATA.angularAcceleration = angularAcceleration;
    }

    /**
     *
     * @return
     */
    public float getAngularTolerance() {
	return DATA.angularTolerance;
    }

    /**
     *
     * @param angularTolerance
     */
    public void setAngularTolerance(float angularTolerance) {
	this.DATA.angularTolerance = angularTolerance;
    }

    /**
     *
     * @return
     */
    public float getBaseCarryWeight() {
	return DATA.baseCarryWeight;
    }

    /**
     *
     * @param baseCarryWeight
     */
    public void setBaseCarryWeight(float baseCarryWeight) {
	this.DATA.baseCarryWeight = baseCarryWeight;
    }

    /**
     *
     * @return
     */
    public float getBaseMass() {
	return DATA.baseMass;
    }

    /**
     *
     * @param baseMass
     */
    public void setBaseMass(float baseMass) {
	this.DATA.baseMass = baseMass;
    }

    /**
     *
     * @return
     */
    public float getDecelerationRate() {
	return DATA.decelerationRate;
    }

    /**
     *
     * @param decelerationRate
     */
    public void setDecelerationRate(float decelerationRate) {
	this.DATA.decelerationRate = decelerationRate;
    }

    /**
     *
     * @return
     */
    public float getFemaleWeight() {
	return DATA.femaleWeight;
    }

    /**
     *
     * @param femaleWeight
     */
    public void setFemaleWeight(float femaleWeight) {
	this.DATA.femaleWeight = femaleWeight;
    }

    /**
     *
     * @return
     */
    public float getFlightRadius() {
	return DATA.flightRadius;
    }

    /**
     *
     * @param flightRadius
     */
    public void setFlightRadius(float flightRadius) {
	this.DATA.flightRadius = flightRadius;
    }

    /**
     *
     * @return
     */
    public float getHealthRegen() {
	return DATA.healthRegen;
    }

    /**
     *
     * @param healthRegen
     */
    public void setHealthRegen(float healthRegen) {
	this.DATA.healthRegen = healthRegen;
    }

    /**
     *
     * @return
     */
    public float getInjuredHealthPct() {
	return DATA.injuredHealthPct;
    }

    /**
     *
     * @param injuredHealthPct
     */
    public void setInjuredHealthPct(float injuredHealthPct) {
	this.DATA.injuredHealthPct = injuredHealthPct;
    }

    /**
     *
     * @return
     */
    public float getMagickaRegen() {
	return DATA.magickaRegen;
    }

    /**
     *
     * @param magickaRegen
     */
    public void setMagickaRegen(float magickaRegen) {
	this.DATA.magickaRegen = magickaRegen;
    }

    /**
     *
     * @return
     */
    public float getMaleHeight() {
	return DATA.maleHeight;
    }

    /**
     *
     * @param maleHeight
     */
    public void setMaleHeight(float maleHeight) {
	this.DATA.maleHeight = maleHeight;
    }

    /**
     *
     * @return
     */
    public float getMaleWeight() {
	return DATA.maleWeight;
    }

    /**
     *
     * @param maleWeight
     */
    public void setMaleWeight(float maleWeight) {
	this.DATA.maleWeight = maleWeight;
    }

    /**
     *
     * @return
     */
    public Size getSize() {
	return DATA.size;
    }

    /**
     *
     * @param size
     */
    public void setSize(Size size) {
	this.DATA.size = size;
    }

    /**
     *
     * @return
     */
    public float getStaminaRegen() {
	return DATA.staminaRegen;
    }

    /**
     *
     * @param staminaRegen
     */
    public void setStaminaRegen(float staminaRegen) {
	this.DATA.staminaRegen = staminaRegen;
    }

    /**
     *
     * @return
     */
    public float getStartingHealth() {
	return DATA.startingHealth;
    }

    /**
     *
     * @param startingHealth
     */
    public void setStartingHealth(float startingHealth) {
	this.DATA.startingHealth = startingHealth;
    }

    /**
     *
     * @return
     */
    public float getStartingMagicka() {
	return DATA.startingMagicka;
    }

    /**
     *
     * @param startingMagicka
     */
    public void setStartingMagicka(float startingMagicka) {
	this.DATA.startingMagicka = startingMagicka;
    }

    /**
     *
     * @return
     */
    public float getStartingStamina() {
	return DATA.startingStamina;
    }

    /**
     *
     * @param startingStamina
     */
    public void setStartingStamina(float startingStamina) {
	this.DATA.startingStamina = startingStamina;
    }

    /**
     *
     * @return
     */
    public float getUnarmedDamage() {
	return DATA.unarmedDamage;
    }

    /**
     *
     * @param unarmedDamage
     */
    public void setUnarmedDamage(float unarmedDamage) {
	this.DATA.unarmedDamage = unarmedDamage;
    }

    /**
     *
     * @return
     */
    public float getUnarmedReach() {
	return DATA.unarmedReach;
    }

    /**
     *
     * @param unarmedReach
     */
    public void setUnarmedReach(float unarmedReach) {
	this.DATA.unarmedReach = unarmedReach;
    }

    /**
     *
     */
    public void clearAttackData() {
	ATKDs.clear();
    }

    /**
     *
     * @return
     */
    public FormID getMaterialType() {
	return NAM4.getForm();
    }

    /**
     *
     * @param id
     */
    public void setMaterialType(FormID id) {
	NAM4.setForm(id);
    }

    /**
     *
     * @return
     */
    public FormID getImpactDataSet() {
	return NAM5.getForm();
    }

    /**
     *
     * @param id
     */
    public void setImpactDataSet(FormID id) {
	NAM5.setForm(id);
    }

    /**
     *
     * @return
     */
    public FormID getDecapitationFX() {
	return NAM7.getForm();
    }

    /**
     *
     * @param id
     */
    public void setDecapitationFX(FormID id) {
	NAM7.setForm(id);
    }

    /**
     *
     * @return
     */
    public FormID getOpenLootSound() {
	return ONAM.getForm();
    }

    /**
     *
     * @param id
     */
    public void setOpenLootSound(FormID id) {
	ONAM.setForm(id);
    }

    /**
     *
     * @return
     */
    public FormID getCloseLootSound() {
	return LNAM.getForm();
    }

    /**
     *
     * @param id
     */
    public void setCloseLootSound(FormID id) {
	LNAM.setForm(id);
    }

    /**
     *
     * @return
     */
    public FormID getUnarmedEquipSlot() {
	return UNES.getForm();
    }

    /**
     *
     * @param id
     */
    public void setUnarmedEquipSlot(FormID id) {
	UNES.setForm(id);
    }

    /**
     *
     */
    public void clearTinting() {
	headData.clear();
    }

    /**
     *
     * @param gender
     * @return
     */
    public String getLightingModels(Gender gender) {
	switch (gender) {
	    case MALE:
		return EGTrecords.set.get(Type.MNAM).MODL.string;
	    default:
		return EGTrecords.set.get(Type.FNAM).MODL.string;
	}
    }

    /**
     *
     * @param gender
     * @param s
     */
    public void setLightingModels(Gender gender, String s) {
	switch (gender) {
	    case MALE:
		EGTrecords.set.get(Type.MNAM).MODL.setString(s);
	    default:
		EGTrecords.set.get(Type.FNAM).MODL.setString(s);
	}
    }

    /**
     *
     * @param gender
     * @return
     */
    public String getPhysicsModels(Gender gender) {
	switch (gender) {
	    case MALE:
		return HKXrecords.set.get(Type.MNAM).MODL.string;
	    default:
		return HKXrecords.set.get(Type.FNAM).MODL.string;
	}
    }

    /**
     *
     * @param gender
     * @param s
     */
    public void setPhysicsModels(Gender gender, String s) {
	switch (gender) {
	    case MALE:
		HKXrecords.set.get(Type.MNAM).MODL.setString(s);
	    default:
		HKXrecords.set.get(Type.FNAM).MODL.setString(s);
	}
    }

    /**
     *
     * @return
     */
    public ArrayList<FormID> getEquipSlots() {
	return SubList.subFormToPublic(QNAM);
    }

    /**
     *
     * @param in
     */
    public void addEquipSlot(FormID in) {
	QNAM.add(new SubForm(Type.QNAM, in));
    }

    /**
     *
     * @param in
     */
    public void removeEquipSlot(FormID in) {
	QNAM.remove(new SubForm(Type.QNAM, in));
    }

    /**
     *
     */
    public void clearEquipSlots() {
	QNAM.clear();
    }
}
